home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 001-025 / disk_010 / iff / readpict.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  289 lines

  1. /** ReadPict.c **************************************************************
  2.  *
  3.  * Read an ILBM raster image file.   01/07/85.
  4.  *
  5.  * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
  6.  * This software is in the public domain.
  7.  *
  8.  * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
  9.  *
  10.  * The IFF reader portion is essentially a recursive-descent parser.
  11.  * This program will look into a CAT or LIST to find a FORM ILBM, but it
  12.  * won't look inside another FORM type for a nested FORM ILBM.
  13.  ****************************************************************************/
  14.  
  15. #define LOCAL   /* static */
  16.  
  17. /* #include "intuall.h" */
  18. #include <libraries/dos.h>
  19. #include <libraries/dosextens.h>
  20. #include "ilbm.h"
  21. #include "readpict.h"
  22.  
  23. /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
  24.  
  25. #define EXDepth 5
  26. #define maxColorReg (1<<EXDepth)
  27. #define MIN(a,b) ((a)<(b)?(a):(b))
  28.  
  29. #define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
  30.  
  31. /* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
  32. #define bufSz 512
  33.  
  34. /*------------- External functions for Manx --------------*/
  35.  
  36. extern IFFP OpenRGroup();
  37. extern IFFP GetFChunkHdr();
  38.  
  39. /*------------ ILBM reader -----------------------------------------------*/
  40. /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
  41.  * We allocate one of these on the stack for every LIST or FORM encountered
  42.  * in the file and use it to hold BMHD & CMAP properties. We also allocate
  43.  * an initial one for the whole file.
  44.  * We allocate a new GroupContext (and initialize it by OpenRIFF or
  45.  * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
  46.  * just a context for reading (nested) chunks.
  47.  *
  48.  * If we were to scan the entire example file outlined below:
  49.  *    reading          proc(s)                new               new
  50.  *
  51.  * --whole file--   ReadPicture+ReadIFF   GroupContext        ILBMFrame
  52.  * CAT              ReadICat                GroupContext
  53.  *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
  54.  *     PROP ILBM    GetPrILBM                   GroupContext
  55.  *       CMAP       GetCMAP
  56.  *       BMHD       GetBMHD
  57.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  58.  *       BODY       GetBODY
  59.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  60.  *       BODY       GetBODY
  61.  *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
  62.  */
  63.  
  64. /* NOTE: For a simple version of this program, set Fancy to 0.
  65.  * That'll compile a program that skips all LISTs and PROPs in the input
  66.  * file. It will look in CATs for FORMs ILBM. That's suitable for most uses.
  67.  *
  68.  * For a fancy version that handles LISTs and PROPs, set Fancy to 1. */
  69. #define Fancy  0
  70.  
  71. /* Global access to client-provided pointers.*/
  72. LOCAL UBYTE *(*gAllocator)() = NL;  /* $$$ changed from NULL */
  73.                           /* Allocator which only needs size parameter.*/
  74. LOCAL struct BitMap *gBM = NL;        /* client's bitmap.*/
  75. LOCAL ILBMFrame *giFrame = NL;        /* "client frame".*/
  76.  
  77. /** GetFoILBM() *************************************************************
  78.  *
  79.  * Called via ReadPicture to handle every FORM encountered in an IFF file.
  80.  * Reads FORMs ILBM and skips all others.
  81.  * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
  82.  * finds no BODY or if it has no BMHD to decode the BODY.
  83.  *
  84.  * Once we find a BODY chunk, we'll allocate the BitMap and read the image.
  85.  *
  86.  ****************************************************************************/
  87. LOCAL BYTE bodyBuffer[bufSz];
  88.  
  89. IFFP GetFoILBM(parent)
  90. GroupContext *parent;
  91. {
  92.    /*compilerBug register*/ IFFP iffp;
  93.    GroupContext formContext;
  94.    ILBMFrame ilbmFrame;         /* only used for non-clientFrame fields.*/
  95.    register int i;
  96.    long plsize;  /* Plane size in bytes. */
  97.    long nPlanes; /* number of planes in our display image */
  98.  
  99.    if (parent->subtype != ID_ILBM)
  100.       return(IFF_OKAY); /* just continue scaning the file */
  101.  
  102.    ilbmFrame = *(ILBMFrame *)parent->clientFrame;
  103.    iffp = OpenRGroup(parent, &formContext);
  104.    CheckIFFP();
  105.  
  106.   do {
  107.     iffp = GetFChunkHdr(&formContext);
  108.     if (iffp == ID_BMHD) {
  109.         ilbmFrame.foundBMHD = TRUE;
  110.         iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
  111.     }
  112.  
  113.     else if (iffp == ID_CMAP) {
  114.         ilbmFrame.nColorRegs = maxColorReg;  /* we have room for this many */
  115.         iffp = GetCMAP(
  116.            &formContext, (WORD *)&ilbmFrame.colorMap, &ilbmFrame.nColorRegs);
  117.     }
  118.  
  119.     else if (iffp == ID_BODY) {
  120.          if (!ilbmFrame.foundBMHD)  return(BAD_FORM);   /* No BMHD chunk! */
  121.  
  122.          nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth);
  123.  
  124.          InitBitMap(
  125.             gBM,
  126.             nPlanes,
  127.            (long)ilbmFrame.bmHdr.w,
  128.            (long)ilbmFrame.bmHdr.h);
  129.  
  130.          plsize = RowBytes(ilbmFrame.bmHdr.w) * ilbmFrame.bmHdr.h;
  131.          /* Allocate all planes contiguously.  Not really necessary,
  132.           * but it avoids writing code to back-out if only enough memory
  133.           * for some of the planes.
  134.           * WARNING: Don't change this without changing the code that
  135.           * Frees these planes.
  136.           */
  137.          if (gBM->Planes[0] =
  138.                 (PLANEPTR)(*gAllocator)(nPlanes * plsize))
  139.             {
  140.             for (i = 1; i < nPlanes; i++)
  141.                 gBM->Planes[i] = (PLANEPTR) gBM->Planes[0] + plsize*i;
  142.             iffp = GetBODY(
  143.                 &formContext,
  144.                 gBM,
  145.                 NULL,
  146.                 &ilbmFrame.bmHdr,
  147.                 bodyBuffer,
  148.                 (long)bufSz);
  149.  
  150.             if (iffp == IFF_OKAY) iffp = IFF_DONE;      /* Eureka */
  151.             *giFrame = ilbmFrame;  /* Copy fields to client's frame.*/
  152.             }
  153.          else
  154.             iffp = CLIENT_ERROR;        /* not enough RAM for the bitmap */
  155.     }
  156.  
  157.     else if (iffp == END_MARK)
  158.              iffp = BAD_FORM;
  159.  
  160.   } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  161.                           * subroutine returned IFF_OKAY (no errors).*/
  162.  
  163.    if (iffp != IFF_DONE)  return(iffp);
  164.  
  165.    /* If we get this far, there were no errors. */
  166.    CloseRGroup(&formContext);
  167.    return(iffp);
  168.    }
  169.  
  170. /** Notes on extending GetFoILBM ********************************************
  171.  *
  172.  * To read more kinds of chunks, just add clauses to the switch statement.
  173.  * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
  174.  * the switch statement in GetPrILBM, too.
  175.  *
  176.  * To read a FORM type that contains a variable number of data chunks--e.g.
  177.  * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
  178.  * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
  179.  * case do whatever cleanup you need.
  180.  *
  181.  ****************************************************************************/
  182.  
  183. /** GetPrILBM() *************************************************************
  184.  *
  185.  * Called via ReadPicture to handle every PROP encountered in an IFF file.
  186.  * Reads PROPs ILBM and skips all others.
  187.  *
  188.  ****************************************************************************/
  189. #if Fancy
  190. IFFP GetPrILBM(parent)
  191. GroupContext *parent;
  192. {
  193.    /*compilerBug register*/ IFFP iffp;
  194.    GroupContext propContext;
  195.    ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
  196.  
  197.    if (parent->subtype != ID_ILBM)
  198.       return(IFF_OKAY); /* just continue scaning the file */
  199.  
  200.    iffp = OpenRGroup(parent, &propContext);
  201.    CheckIFFP();
  202.  
  203.    do switch (iffp = GetPChunkHdr(&propContext)) {
  204.       case ID_BMHD: {
  205.         ilbmFrame->foundBMHD = TRUE;
  206.         iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
  207.         break; }
  208.       case ID_CMAP: {
  209.         ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */
  210.         iffp = GetCMAP(
  211.           &propContext, (WORD *)&ilbmFrame->colorMap, &ilbmFrame->nColorRegs);
  212.         break; }
  213.       } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  214.                           * subroutine returned IFF_OKAY (no errors).*/
  215.  
  216.    CloseRGroup(&propContext);
  217.    return(iffp == END_MARK ? IFF_OKAY : iffp);
  218.    }
  219. #endif
  220.  
  221. /** GetLiILBM() *************************************************************
  222.  *
  223.  * Called via ReadPicture to handle every LIST encountered in an IFF file.
  224.  *
  225.  ****************************************************************************/
  226. #if Fancy
  227. IFFP GetLiILBM(parent)  GroupContext *parent;  {
  228.     ILBMFrame newFrame; /* allocate a new Frame */
  229.  
  230.     newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
  231.  
  232.     return( ReadIList(parent, (ClientFrame *)&newFrame) );
  233.     }
  234. #endif
  235.  
  236. /** ReadPicture() ***********************************************************
  237.  *
  238.  * Read a picture from an IFF file, given a file handle open for reading.
  239.  * Allocates BitMap using (*Allocator)().
  240.  *
  241.  ****************************************************************************/
  242. IFFP ReadPicture(file, bm, iFrame, Allocator)
  243.    LONG file;
  244.    struct BitMap *bm;
  245.    ILBMFrame *iFrame;      /* Top level "client frame".*/
  246.    UBYTE *(*Allocator)();  /* Allocation procedure which only requires
  247.                             * size parameter.  That is, no flags parameter.
  248.                             * Must be in Chip memory, for bitmap data.*/
  249.    {
  250.    IFFP iffp = IFF_OKAY;
  251.  
  252. #if Fancy
  253.    iFrame->clientFrame.getList = GetLiILBM;
  254.    iFrame->clientFrame.getProp = GetPrILBM;
  255. #else
  256.    iFrame->clientFrame.getList = SkipGroup;
  257.    iFrame->clientFrame.getProp = SkipGroup;
  258. #endif
  259.    iFrame->clientFrame.getForm = GetFoILBM;
  260.    iFrame->clientFrame.getCat  = ReadICat ;
  261.  
  262.    /* Initialize the top-level client frame's property settings to the
  263.     * program-wide defaults. This example just records that we haven't read
  264.     * any BMHD property or CMAP color registers yet. For the color map, that
  265.     * means the default is to leave the machine's color registers alone.
  266.     * If you want to read a property like GRAB, init it here to (0, 0). */
  267.    iFrame->foundBMHD  = FALSE;
  268.    iFrame->nColorRegs = 0;
  269.  
  270.    gAllocator = Allocator;
  271.    gBM = bm;
  272.    giFrame = iFrame;
  273.   /* Store a pointer to the client's frame in a global variable so that
  274.    * GetFoILBM can update client's frame when done.  Why do we have so
  275.    * many frames & frame pointers floating around causing confusion?
  276.    * Because IFF supports PROPs which apply to all FORMs in a LIST,
  277.    * unless a given FORM overrides some property.
  278.    * When you write code to read several FORMs,
  279.    * it is essential to maintain a frame at each level of the syntax
  280.    * so that the properties for the LIST don't get overwritten by any
  281.    * properties specified by individual FORMs.
  282.    * We decided it was best to put that complexity into this one-FORM example,
  283.    * so that those who need it later will have a useful starting place.
  284.    */
  285.  
  286.    iffp = ReadIFF(file, (ClientFrame *)iFrame);
  287.    return(iffp);
  288.    }
  289.